package org.zn.note.jdk.java8.Java8InAction;

import org.zn.note.jdk.java8.Java8InAction.bean.Apple;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 第4章 引入流
 * <p>
 * {@link Stream} 流是什么：“从支持数据处理操作的源生成的元素序列”
 * 1、元素序列：集合、流都是元素序列，流也想集合一样有接口可以访问元素。集合用于存取，流用于计算。
 * 2、源：提供数据的源，比如集合、数组、输入/输出资源等。有序集合生成的流保留原有顺序，列表生成的流元素顺序也一致。
 * 3、数据处理：类似数据库操作，如filter、map、reduce、find、match、sort等。流操作可以顺序、可以并行。
 * 4、流水线：流本身也返回流，用于下一个运算，就像Linux的管道。
 * 5、内部迭代：集合是用迭代器显示操作，流的迭代操作是背后的。
 * （例子 ${@link Ch4#streamExample1()}）
 * <p>
 * 流和集合的区别 ${@link Ch4#streamExample2()}
 * 1、集合中是完整的数据，像DVD，有完整电影。流中是从源取一些、计算一些，像在线视频，缓冲一点就可以看一点。
 * 2、流只能遍历一次！
 * 3、集合外部迭代，流内部迭代
 * <p>
 * 中间操作&终端操作、短路&循环合并  ${@link Ch4#streamExample3()}
 * 对于流的操作分两种：中间操作、终端操作
 * 中间操作类似filter、sorted等，操作后还是生成一个新流
 * 终端操作类似count(返回long)、foreach(返回void)等，所有返回非流的，都是终端操作
 */
class Ch4 {

    private static void streamExample1() {
        List<Apple> apples = Apple.getApples();
        List redAppleWeights =
                apples.stream() // 从源生成流
                        // 数据处理，除了最后的collect，都返回一个流
                        .filter(apple -> apple.getColor() == "red") // (内部迭代)选出红色苹果
                        .map(Apple::getWeight) // (内部迭代)获取重量
                        .limit(3) // 选出3个
                        .collect(Collectors.toList()); // 结果保存到一个List中
        System.out.println(redAppleWeights);
    }

    // Stream只能遍历一遍
    private static void streamExample2() {
        List<String> title = Arrays.asList("java8", "in", "action");
        Stream<String> s = title.stream();
        s.forEach(System.out::println);
        // java.lang.IllegalStateException: stream has already been operated upon or closed
        s.forEach(System.out::println);
    }

    /*
    关于流中间操作和终端操作、短路和循环合并
    步骤一：apples.stream().forEach(System.out::println);
            ① .forEach返回的是void，所以是终端操作。这样可以打印出所以的List内容。
    步骤二：apples.stream().filter().map().limit().collect()
            ① filter().map().limit()都是中间操作，collect()是终端操作
            ② 短路：filter和map中只是打了前3个，因为后面有limit(3)
            ③ 循环合并：filter和map在打印时是交替的，所以他们在一个循环里
     */
    private static void streamExample3() {
        List<Apple> apples = Apple.getApples();
        /*
        步骤一：打印出全部的apples
number:1, color:red, weight:100
number:2, color:red, weight:120
number:3, color:red, weight:150
number:4, color:red, weight:200
number:5, color:green, weight:100
number:6, color:green, weight:120
number:7, color:green, weight:150
number:8, color:green, weight:200
         */
        apples.stream().forEach(System.out::println);

        /*
        步骤二：打印结果
filter: number:1, color:red, weight:100
map: number:1, color:red, weight:100
filter: number:2, color:red, weight:120
map: number:2, color:red, weight:120
filter: number:3, color:red, weight:150
map: number:3, color:red, weight:150
[1, 2, 3]
         */
        List redAppleWeights =
                apples.stream()
                        .filter(apple -> {
                            System.out.println("filter: " + apple);
                            return apple.getColor() == "red";
                        })
                        .map(apple -> {
                            System.out.println("map: " + apple);
                            return apple.number;
                        })
                        .limit(3)
                        .collect(Collectors.toList());
        System.out.println(redAppleWeights);
    }

    public static void main(String[] args) {
        streamExample3();
    }
}
